package com.protocols.sctp;
import java.rmi.*;

import java.rmi.registry.*;

import java.rmi.server.*;
import java.util.Arrays;
import java.util.Properties;
import java.util.Random;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.*;
import java.nio.ByteBuffer;

import com.Main.MyServiceInterface;
import com.protocols.GeneralProtocolData;
import com.protocols.ProtoOperations;
import com.protocols.sctp.m3ua.M3uaASPAC;
import com.protocols.sctp.m3ua.M3uaHandler;
import com.protocols.sctp.m3ua.M3uaHandlerInterface;
import com.sun.nio.sctp.MessageInfo;
import com.sun.nio.sctp.SctpChannel;



 

public class SctpHandler extends java.rmi.server.UnicastRemoteObject implements SctpHandlerInterface,MyServiceInterface{

    private SctpChannel sctpChannel;
	private Registry Registry;  
    private M3uaHandlerInterface M3uaHandler;
    public Logger Log = Logger.getLogger(this.getClass().getName());
    Boolean logInfoEnabled=false;
    
    
    // Default Configuration
    int layerServiceport=9001;
	String sctphandlerurl= "SctpHandler";
	String sctpPeerIp=	"localhost";
	int sctpPeerPort=2906;		
	String m3uahandlerurl= "M3uaHandler";
	int ConnRetry=3000;		
	String logfile= "var/log/sctp.log";
	Level loglevel= Level.OFF;
	String sctpMode="client";
	
		  
    public SctpHandler() throws RemoteException {
		super();
	}

    public void initialise() throws Exception{	
		
			// Loading the Config File
			Properties properties=null;
			try{			
				properties = new java.util.Properties();
				properties.load( new FileInputStream("General.conf"));
			}catch( IOException e){
				System.out.println("Couldn't locate the Config File");				
				
			}
			
			// Configuring the Logger
			logfile= properties.getProperty("sctp.log.filepath");
			loglevel= Level.parse(properties.getProperty("sctp.log.level"));
						
			FileHandler filehandler=null;
			try{
				filehandler= new FileHandler(logfile,true);
				filehandler.setFormatter(new SimpleFormatter());
				Log.addHandler(filehandler);
				Log.setLevel(loglevel);				
			}catch( IOException e){
				System.out.println("Issue Opening the Log File. Setting the Log Level to 'OFF'"+"Exception Occured :" +e.getClass().getSimpleName()+":"+ Arrays.toString(e.getStackTrace()));
				Log.setLevel(Level.OFF);	
			}
			
			logInfoEnabled=Log.isLoggable(Level.INFO);	
			
			// Layer Service Initialisation
			
			layerServiceport=Integer.valueOf(properties.getProperty("layerservice.port"));
			sctphandlerurl= properties.getProperty("sctp.layerservice.url");
			sctpPeerIp=	properties.getProperty("sctp.peer.ip");
			sctpPeerPort=Integer.valueOf(properties.getProperty("sctp.peer.port"));		
			m3uahandlerurl= properties.getProperty("m3ua.layerservice.url");
			ConnRetry=Integer.valueOf(properties.getProperty("connectionretryinterval"));	
			sctpMode=properties.getProperty("sctp.mode");
			
			// Obtaining the Registry	
			try{
				Registry = LocateRegistry.createRegistry( layerServiceport );
				if(logInfoEnabled)Log.info("Created Registry on Port:"+layerServiceport);
			}catch(RemoteException e){
				Registry = LocateRegistry.getRegistry( layerServiceport );	
				if(logInfoEnabled)Log.info("Obtained Registry from Port:"+layerServiceport);
			}
				
			// Starting the Layer Service	
			Registry.rebind(sctphandlerurl, this);			
			if(logInfoEnabled)Log.info("Bound SCTP Handler on Url:"+sctphandlerurl);
		
		
	}

    
	private void establishSctpClientConnection() throws Exception
	{	
		Boolean retry=true;
		while(retry)
		{
			try{
				
				sctpChannel = SctpChannel.open();//(socketAddress, 1 ,1 );  
	            sctpChannel.bind(new InetSocketAddress("10.24.8.17", 2905));
	            sctpChannel.connect( new InetSocketAddress(sctpPeerIp, sctpPeerPort));   //, 1 ,1
	            
	            retry=false;
			}catch(IOException e){	
				Log.severe("Couldn't Establish the SCTP Connection to "+sctpPeerIp+":"+sctpPeerPort+". Retry in "+ConnRetry+" Secs."+"Exception Occured :" +e.getClass().getSimpleName()+":"+ Arrays.toString(e.getStackTrace()));
				Thread.sleep(ConnRetry);
			}
		}
		if(logInfoEnabled)Log.info("Established the SCTP Connection to "+sctpPeerIp+":"+sctpPeerPort);
		
	}
	
	private void establishM3uaConnection()throws Exception
	{	
		Boolean retry=true;
		while(retry)
		{
			try{
				M3uaHandler=(M3uaHandlerInterface)(Registry.lookup(m3uahandlerurl));
				retry=false;
			}catch(Exception e){	
				Log.severe("Couldn't Obtained the M3UA Instance. Retry in "+ConnRetry+" Secs."+"Exception Occured :" +e.getClass().getSimpleName()+":"+ Arrays.toString(e.getStackTrace()));
				Thread.sleep(ConnRetry);
			}
		}				
		if(logInfoEnabled)Log.info("Obtained M3uaHandler Instance");

		
		
	}


    public void StartClientOperation() throws Exception{
    	try{
	    	int count=0;
	    	
	    	while ( true){
				ByteBuffer buff =  ByteBuffer.allocate(1024);
				MessageInfo messageinfo= sctpChannel.receive(buff, null,null);
				
				buff.position(0);
				byte [] input = new byte[messageinfo.bytes()];
				buff.get(input,0,messageinfo.bytes());
				
				int length=input.length;			  
				  if(length>0){		
					  if(logInfoEnabled)Log.info("Received Byte Stream, Creating the Thread:"+ProtoOperations.getHexString(input));
					  new TreatInCommingSctp(ProtoOperations.extractByteArray(input, 0, length), M3uaHandler, sctpChannel,Log,  new Random().nextInt(1000000000)).start();
				  }	
				  else if(length==-1){		
					  // Socket Disconnected from Server
					  establishSctpClientConnection();
				  }		  
				  
			  }
	    		
	    
    	}catch(IOException e){
    		establishSctpClientConnection();
    		StartClientOperation();
	    }
    }
    	
	  
    public void StartServerOperation() throws Exception{
    	/*
    	try{	    	    	
	    	while(true){			
	    		
	    		SocketAddress serverSocketAddress = new InetSocketAddress(1111);
	            System.out.println("create and bind for sctp address");
	            SctpServerChannel sctpServerChannel =  SctpServerChannel.open().bind(serverSocketAddress);
	            System.out.println("address bind process finished successfully"); 
	            
	            
				ServerSocket welcomeSocket = new ServerSocket(sctpPeerPort);
				mySocket = welcomeSocket.accept();      
			     
				outStream = new DataOutputStream(mySocket.getOutputStream());
				inStream = new DataInputStream(mySocket.getInputStream());
				if(logInfoEnabled)Log.info("Client Connection Accepted:"+mySocket.getRemoteSocketAddress().toString());
				  
				byte []input =new byte[300];
				
				while ( true){
				  int length=inStream.read(input);
				  
				  if(length>0){
					  if(logInfoEnabled)Log.info("Received Byte Stream, Creating the Thread:"+ProtoOperations.getHexString(input));
					  new TreatInCommingTcp(ProtoOperations.extractByteArray(input, 0, length), M3uaHandler, outStream, new Random().nextInt(1000000000)).start();
				  }						  
				 }
				
			}
	    	
	    	
	    	
    	}catch(IOException e){
    		
	    }
	    */
    }
    

	
    




	@Override
	public void startLayer() throws Exception {
		
		try{
			initialise();
			if (sctpMode.equals("client")){
				establishSctpClientConnection();
				establishM3uaConnection();
				StartClientOperation();	
			}
			else{
				establishM3uaConnection();
				StartServerOperation();
			}
			
			
			// Self Check			
			
			
			
		}catch(Exception e){
			Log.severe("Exception Occured :" +e.getClass().getSimpleName()+":"+ Arrays.toString(e.getStackTrace()));
			
		}
		
	}
   
	   

	@Override
	public void m3uaToSctp(long sessionid,GeneralProtocolData m3uamsg) throws RemoteException {
		try{
			 final ByteBuffer byteBuffer = ByteBuffer.allocate(9000);            
	            byte [] message = ((GeneralProtocolData)m3uamsg).getByteArray();
	            final MessageInfo messageInfo = MessageInfo.createOutgoing(null, 0);            
	            messageInfo.payloadProtocolID(3); 
	            
	            if (m3uamsg.getClass().getSimpleName().equals("M3uaPayLoadData")){
	            	messageInfo.streamNumber(1);
	            }
	            else{
	            	messageInfo.streamNumber(0);
	            }
	            byteBuffer.put(message);
	            byteBuffer.flip();
	            
	            sctpChannel.send(byteBuffer, messageInfo);
	       
		}catch(Exception e){
			Log.severe("Exception Occured :" +e.getClass().getSimpleName()+":"+ Arrays.toString(e.getStackTrace()));
		}
		
	}

	public static void main(String args[]) throws Exception {
		
		SctpHandler sctp = new SctpHandler();
		try{
			sctp.initialise();
			if (sctp.sctpMode.equals("client")){
				sctp.establishSctpClientConnection();
				sctp.establishM3uaConnection();
				sctp.StartClientOperation();	
			}
			else{
				sctp.establishM3uaConnection();
				sctp.StartServerOperation();
			}
			
			
			// Self Check			
			
			
			
		}catch(Exception e){
			sctp.Log.severe("Exception Occured :" +e.getClass().getSimpleName()+":"+ Arrays.toString(e.getStackTrace()));
			
		}
		
	}


   
}